import { Vector2 } from "../src/vector/Vector2";
import { TestBase } from "./TestBase";
import { Precision } from "../src/Precision";
import { XY } from "../src/point/XY";

export class TestVector2 extends TestBase {
    public async runAllTests() {
        console.log('开始运行 Vector2 测试...');

        this.testConstruction();
        this.testBasicOperations();
        this.testNormalization();
        this.testDotProduct();
        this.testCrossProduct();
        this.testRotation();
        this.testAngles();
        this.testCloning();
        this.testEdgeCases();

        console.log('Vector2 测试完成！');
    }

    /**
     * @description 测试向量构造
     */
    private testConstruction() {
        console.log('测试向量构造...');

        // 测试默认构造
        const v1 = new Vector2();
        this.assert(v1.x === 0 && v1.y === 0, '默认构造应该创建零向量');

        // 测试带参数构造
        const v2 = new Vector2(3, 4);
        this.assert(v2.x === 3 && v2.y === 4, '带参数构造应该正确设置坐标');

        // 测试从XY构造
        const xy = new XY(1, 2);
        const v3 = new Vector2(xy.x, xy.y);
        this.assert(v3.x === 1 && v3.y === 2, '从XY构造应该正确设置坐标');

        console.log('✓ 向量构造测试通过');
    }

    /**
     * @description 测试基本运算
     */
    private testBasicOperations() {
        console.log('测试基本运算...');

        const v1 = new Vector2(1, 2);
        const v2 = new Vector2(3, 4);

        // 测试加法
        const sum = v1.add(v2);
        this.assert(sum.x === 4 && sum.y === 6, '向量加法计算错误');

        // 测试减法
        const diff = v2.subtract(v1);
        this.assert(diff.x === 2 && diff.y === 2, '向量减法计算错误');

        // 测试数乘
        const scaled = v1.multiply(2);
        this.assert(scaled.x === 2 && scaled.y === 4, '向量数乘计算错误');

        // 测试长度
        const v3 = new Vector2(3, 4);
        this.assert(Math.abs(v3.length() - 5) < Precision.EPSILON5, '向量长度计算错误');

        console.log('✓ 基本运算测试通过');
    }

    /**
     * @description 测试归一化
     */
    private testNormalization() {
        console.log('测试归一化...');

        // 测试普通向量归一化
        const v1 = new Vector2(3, 4);
        const normalized = v1.normalize();
        this.assert(Math.abs(normalized.length() - 1) < Precision.EPSILON5, '归一化后长度应为1');
        this.assert(Math.abs(normalized.x - 0.6) < Precision.EPSILON5 &&
            Math.abs(normalized.y - 0.8) < Precision.EPSILON5, '归一化计算错误');

        // 测试零向量归一化
        const zero = new Vector2(0, 0);
        const normalizedZero = zero.normalize();
        this.assert(normalizedZero.x === 0 && normalizedZero.y === 0, '零向量归一化应返回零向量');

        // 测试指定长度的归一化
        const v2 = new Vector2(1, 0);
        const normalized2 = v2.normalize(2);
        this.assert(Math.abs(normalized2.length() - 2) < Precision.EPSILON5, '指定长度归一化错误');

        console.log('✓ 归一化测试通过');
    }

    /**
     * @description 测试点积
     */
    private testDotProduct() {
        console.log('测试点积...');

        const v1 = new Vector2(1, 0);
        const v2 = new Vector2(0, 1);
        const v3 = new Vector2(2, 3);

        // 测试垂直向量点积
        this.assert(v1.dot(v2) === 0, '垂直向量点积应为0');

        // 测试平行向量点积
        this.assert(v1.dot(new Vector2(2, 0)) === 2, '平行向量点积计算错误');

        // 测试一般向量点积
        this.assert(v1.dot(v3) === 2, '一般向量点积计算错误');

        console.log('✓ 点积测试通过');
    }

    /**
     * @description 测试叉积
     */
    private testCrossProduct() {
        console.log('测试叉积...');

        const v1 = new Vector2(1, 0);
        const v2 = new Vector2(0, 1);
        const v3 = new Vector2(2, 3);

        // 测试垂直向量叉积
        this.assert(v1.cross(v2) === 1, '垂直向量叉积计算错误');

        // 测试平行向量叉积
        this.assert(v1.cross(new Vector2(2, 0)) === 0, '平行向量叉积应为0');

        // 测试一般向量叉积
        this.assert(v1.cross(v3) === 3, '一般向量叉积计算错误');

        console.log('✓ 叉积测试通过');
    }

    /**
     * @description 测试旋转
     */
    private testRotation() {
        console.log('测试旋转...');

        const v1 = new Vector2(1, 0);

        // 测试90度旋转
        const rotated90 = v1.rotate(Math.PI / 2);
        this.assert(Math.abs(rotated90.x) < Precision.EPSILON5 &&
            Math.abs(rotated90.y - 1) < Precision.EPSILON5, '90度旋转计算错误');

        // 测试180度旋转
        const rotated180 = v1.rotate(Math.PI);
        this.assert(Math.abs(rotated180.x + 1) < Precision.EPSILON5 &&
            Math.abs(rotated180.y) < Precision.EPSILON5, '180度旋转计算错误');

        // 测试绕点旋转
        const center = new XY(1, 1);
        const v2 = new Vector2(2, 1);  // 向量(2,1)
        const rotatedAroundPoint = v2.rotate(Math.PI / 2, center);
        // 这里的期望值是错误的，让我们重新计算
        // 向量(2,1)绕点(1,1)旋转90度后：
        // 1. 向量起点(0,0)绕(1,1)旋转90度 -> (2,0)
        // 2. 向量终点(2,1)绕(1,1)旋转90度 -> (1,2)
        // 3. 最终向量 = (1,2) - (2,0) = (-1,2)
        this.assert(Math.abs(rotatedAroundPoint.x + 1) < Precision.EPSILON5 &&
            Math.abs(rotatedAroundPoint.y - 2) < Precision.EPSILON5, '绕点旋转计算错误');

        console.log('✓ 旋转测试通过');
    }

    /**
     * @description 测试角度计算
     */
    private testAngles() {
        console.log('测试角度计算...');

        const v1 = new Vector2(1, 0);
        const v2 = new Vector2(0, 1);
        const v3 = new Vector2(-1, 0);

        // 测试90度角
        this.assert(Math.abs(v1.angleTo(v2) - Math.PI / 2) < Precision.EPSILON5, '90度角计算错误');

        // 测试180度角
        this.assert(Math.abs(v1.angleTo(v3) - Math.PI) < Precision.EPSILON5, '180度角计算错误');

        // 测试45度角
        const v4 = new Vector2(1, 1);
        this.assert(Math.abs(v1.angleTo(v4) - Math.PI / 4) < Precision.EPSILON5, '45度角计算错误');

        console.log('✓ 角度计算测试通过');
    }

    /**
     * @description 测试克隆和复制
     */
    private testCloning() {
        console.log('测试克隆和复制...');

        const v1 = new Vector2(3, 4);

        // 测试克隆
        const cloned = v1.clone();
        this.assert(cloned.x === v1.x && cloned.y === v1.y, '克隆应创建相同的向量');

        // 测试克隆独立性
        cloned.x = 5;
        this.assert(v1.x === 3, '修改克隆不应影响原向量');

        // 测试复制
        const v2 = new Vector2();
        v2.copyFrom(v1);
        this.assert(v2.x === v1.x && v2.y === v1.y, '复制应创建相同的向量');

        console.log('✓ 克隆和复制测试通过');
    }

    /**
     * @description 测试边界情况
     */
    private testEdgeCases() {
        console.log('测试边界情况...');

        // 测试零向量操作
        const zero = new Vector2(0, 0);
        this.assert(zero.length() === 0, '零向量长度应为0');
        this.assert(zero.normalize().equals(zero), '零向量归一化应返回零向量');

        // 测试极小向量
        const tiny = new Vector2(Precision.EPSILON5, Precision.EPSILON5);
        this.assert(tiny.length() > 0, '极小向量长度应大于0');

        // 测试极大向量
        const huge = new Vector2(Number.MAX_VALUE, Number.MAX_VALUE);
        this.assert(huge.length() > 0, '极大向量长度应有效');

        // 测试NaN和Infinity
        try {
            new Vector2(NaN, 1);
            this.assert(false, '应该拒绝NaN坐标');
        } catch (e) {
            // 期望抛出异常
        }

        console.log('✓ 边界情况测试通过');
    }
}